#include "hv_HttpServer.hpp"   // 引入 HttpServer 封装类
#include "hv_TcpServer.hpp"    // 引入 TcpServer 封装类

#include <iostream>
#include <Windows.h>

void http() {
    // 1. 创建服务器实例，监听 0.0.0.0:80
    xdg::HttpServer server("0.0.0.0", 80);

    // 2. 注册服务和路由
    // a) 注册静态文件服务，将 URL 根路径 "/" 映射到本地的 "./root" 目录，(确保在运行程序的目录下有 root/index.html 文件)
    server.Static("/", "./root");
    server.setErrorPage("404.html"); // 设置404错误页面

    // b) 注册一个快速的同步路由 (在 I/O 线程中执行)
    server.addSyncRoute("GET", "/ping",
        [](HttpRequest* req, HttpResponse* resp) {
            return resp->String("ping success.");
        }
    );

    // c) 注册一个带动态路径参数的路由 (使用 Context Handler)
    server.addCtxRoute("GET", "/user/{id}",
        [](const HttpContextPtr& ctx) {
            std::string user_id = ctx->param("id");
            hv::Json resp_json;
            resp_json["user_id"] = user_id;
            resp_json["message"] = "Hello from a context handler!";
            return ctx->send(resp_json.dump(2));
        }
    );

    // d) 注册一个耗时的异步路由 (在后台线程池中执行)
    server.addAsyncRoute("GET", "/sleep",
        [](const HttpRequestPtr& req, const HttpResponseWriterPtr& writer) {
            // 1. (可选) 设置状态码，默认为 200 OK
            writer->WriteStatus(HTTP_STATUS_OK);

            // 2. (可选) 设置响应头
            // 分块传输，先设置："Content-Type", "text/plain"（纯文本 (Plain Text) 格式）
            // 后设置 - 长度未知时的响应头："Transfer-Encoding", "chunked"
            // 后设置 - 长度未知时的响应头："Content-Length"
            writer->WriteHeader("Content-Type", "application/json");
            writer->WriteHeader("X-Custom-Header", "MyValue");

            // 3. (可选) 发送响应头（如果需要分块发送响应体）
            // 如果你准备一次性发送所有body，可以省略这一步，End()会自动处理
            // 如果你要分块发送，或者实现SSE，则必须先调用 EndHeaders()
            // writer->EndHeaders(); 

            // 4. (可选) 写入响应体
            std::this_thread::sleep_for(std::chrono::seconds(2));  // 模拟一个耗时2秒的任务
            hv::Json resp_json;
            resp_json["message"] = "Slept for 2 seconds in a worker thread.";
            writer->WriteBody(resp_json.dump(2));
            
            // 5. (必须) 结束响应
            // End() 函数会完成所有数据的发送，并（根据情况）关闭连接
            // 如果之前没有调用 EndHeaders()，它会先发送响应头，再发送响应体
            writer->End();
        }
    );

    // 3. 启动服务器
    server.start(); // 阻塞运行
}

void tcp() { 
    // 1. 创建服务器实例，使用封装的 xdg::TcpServer 类，监听 127.0.0.1:8080
    xdg::TcpServer server("127.0.0.1", 8080);

    // 2. 使用定义的枚举来设置解包规则，服务器将自动处理TCP粘包/半包问题
    server.setUnpack(xdg::TcpServer::UnpackMode::LENGTH_FIELD_32BIT);

    // 3. 注册回调函数
    // 设置连接建立与断开时的回调
    server.onConnection([](const hv::SocketChannelPtr& channel) {
        if (channel->isConnected()) {
            printf("回调 [onConnection]: 客户端 [%s] 已连接。\n", channel->peeraddr().c_str());
        }                                                    
        else {                                              
            printf("回调 [onConnection]: 客户端 [%s] 已断开。\n", channel->peeraddr().c_str());
        }
    });

    // 设置消息处理回调（在异步线程池中执行，可以慢）
    server.onMessage([](const hv::TcpServer::TSocketChannelPtr& channel, hv::Buffer* buf) {

        std::vector<char> recBuf( (const char*)buf->data(), (const char*)buf->data() + buf->size());

        printf("回调 [onMessage]: '收到'来自 [%s] 的消息：\n", channel->peeraddr().c_str());
        for (size_t i = 0; i < recBuf.size(); i++) {
            printf("%02X ", (unsigned char)recBuf[i]);
        }
        printf("\n");

        // 模拟耗时处理
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));

        std::string remsg = "Hello from a message handler!"; // 回复消息

        std::string packet;  // 创建一个空的数据包
        uint32_t body_len = remsg.length();  // 1. 获取消息体长度
        packet.append(reinterpret_cast<const char*>(&body_len), 4);  // 2. 先将4字节的长度头拼接到包中
        packet.append(remsg); // 3. 再将消息体本身拼接到包中

        printf("回调 [onMessage]: '回复'来自 [%s] 的消息：\n", channel->peeraddr().c_str());
        for (size_t i = 0; i < packet.size(); i++) {
            printf("%02X ", (unsigned char)packet[i]);
        }
        printf("\n");

        // 回复客户端（线程安全）
        channel->write(packet);
        });

    // 4. 启动服务器
    server.start(false); // 以非阻塞方式启动，主线程可以继续执行

    printf("服务器已在后台启动。监听端口: 8080\n");
    printf("\n>>> 输入 'q' 或 'quit' 或 '回车' 后按回车键来停止服务器 <<<\n\n");

    // 阻塞主线程，等待用户输入退出指令
    std::string line;
    while (std::getline(std::cin, line)) {
        if (line == "q" || line == "quit" || line.empty()) {
            break;
        }
    }

    // 5. 停止服务器
    server.stop();
    printf("服务器已停止。\n");

}

int main(int argc, char** argv) {

    // 设置控制台为utf8
    SetConsoleOutputCP(CP_UTF8);

    tcp();

    return 0;
}